一、為什麼需要病患詳細資料頁面?
前幾篇文章中,我們已經完成病患清單、搜尋、修改和刪除功能。
不過,當使用者在清單中找到某一筆資料時,可能還需要查看這位病患的完整資訊。
如果把所有資訊都塞在清單裡,畫面不但容易變得擁擠,也不利於後續擴充。
因此,今天要新增一個功能:點選病患編號,就能進入該筆資料的詳細頁面。
這次我們會使用:
二、先認識單筆資料查詢
之前我們使用過:
SELECT id, name, gender, birthday, phone
FROM patient;
這個查詢會取得多筆資料。
如果只想查詢編號為 1 的病患,就可以加上 WHERE:
SELECT id, name, gender, birthday, phone
FROM patient
WHERE id = 1;
這樣就能取得指定編號的紀錄。
實際開發時,不應直接把使用者輸入的內容拼接到 SQL,而是透過參數化查詢處理。
三、建立 PatientDetailServlet
接下來建立 PatientDetailServlet.java。
這個 Servlet 會從網址取得病患編號,再向資料庫查詢對應的資料。
package servlet;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import model.Patient;
import util.DBConnection;
@WebServlet("/patient/detail")
public class PatientDetailServlet extends HttpServlet {
@Override
protected void doGet(
HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
String idText = request.getParameter("id");
int id;
try {
id = Integer.parseInt(idText);
if (id <= 0) {
throw new NumberFormatException();
}
} catch (NumberFormatException e) {
response.sendError(
HttpServletResponse.SC_BAD_REQUEST,
"病患編號格式不正確"
);
return;
}
String sql = "SELECT id, name, gender, birthday, phone "
+ "FROM patient WHERE id = ?";
Patient patient = null;
try (
Connection conn = DBConnection.getConnection();
PreparedStatement ps = conn.prepareStatement(sql)
) {
ps.setInt(1, id);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
patient = new Patient(
rs.getInt("id"),
rs.getString("name"),
rs.getString("gender"),
rs.getDate("birthday"),
rs.getString("phone")
);
}
}
} catch (SQLException e) {
throw new ServletException("取得病患資料失敗", e);
}
if (patient == null) {
response.sendError(
HttpServletResponse.SC_NOT_FOUND,
"找不到這筆病患資料"
);
return;
}
request.setAttribute("patient", patient);
request.getRequestDispatcher("/patient-detail.jsp")
.forward(request, response);
}
}
這段程式沿用了 Day 19 建立的 Patient.java。
如果你之前的類別名稱、套件名稱或欄位不同,記得配合自己的專案調整。
四、看懂程式的關鍵部分
String idText = request.getParameter("id");
getParameter() 會取得請求中的參數值。
例如網址:
/patient/detail?id=1
就會取得字串 "1"。
但要注意,使用者輸入的資料不能直接當成整數使用,所以還需要轉型並檢查格式。
String sql =
"SELECT id, name, gender, birthday, phone "
+ "FROM patient WHERE id = ?";
再透過:
ps.setInt(1, id);
將病患編號傳入 SQL。
這樣可以避免直接拼接使用者輸入的內容,也讓查詢條件更容易維護。
request.setAttribute("patient", patient);
這行會將查詢到的病患物件放進 request,讓 JSP 可以使用。
接著:
request.getRequestDispatcher("/patient-detail.jsp")
.forward(request, response);
就會將請求轉交給 JSP,顯示詳細資料。
五、建立 patient-detail.jsp
接著建立 patient-detail.jsp:
<%@ page contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" %>
<%@ taglib prefix="c"
uri="jakarta.tags.core" %>
這裡使用 <c:out> 輸出欄位內容,可以減少直接輸出文字時的 HTML 注入風險。
記得確認專案已加入相容版本的 JSTL/Jakarta Tags 依賴。
六、如何從病患清單進入詳細頁面?
回到 Day 19 的病患清單 JSP,將病患編號改成連結:
使用者點選編號後,就會進入對應的詳細資料頁面。
例如:
http://localhost:8080/你的專案名稱/patient/detail?id=1
請將「你的專案名稱」換成自己的專案 Context Path。
如果找不到指定編號,Servlet 就會回傳 404 錯誤,而不是顯示一個空白的詳細資料頁面。
七、正式系統還需要注意什麼?
這次我們只練習基本的資料查詢和頁面呈現。
實際的醫療資訊系統還需要確認:
即使網址中的病患編號可以被修改,也不能因此讓使用者任意查看其他人的資料。每次查詢都必須在伺服器端檢查權限。
今日小結
今天我們完成了病患詳細資料頁面,學會:
Day 23 完成!
下一篇,我們要來處理另一個重要問題:使用者輸入的資料不一定正確,因此系統需要在儲存之前進行表單驗證。
參考資料:Jakarta Servlet 官方文件